package com.hospital.search.module.schedule;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.indices.GetAliasResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hospital.common.dto.search.module.PostInsertDto;
import com.hospital.common.pojo.TPostMeta;
import com.hospital.common.utils.LocalDateTimeUtils;
import com.hospital.search.module.exception.SearchServiceException;
import com.hospital.search.module.exception.enums.SearchServiceExpCode;
import com.hospital.search.module.service.TPostMetaService;
import com.hospital.search.module.utils.ElasticInsertUtils;
import com.hospital.search.module.utils.PostIndexManager;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Component
public class RebuildIndex {
    @Autowired
    private ElasticsearchClient esClient;
    @Autowired
    private PostIndexManager postIndexManager;
    @Autowired
    private ElasticInsertUtils elasticInsertUtils;
    @Autowired
    private TPostMetaService tPostMetaService;
    @Value("${elastic.index-alias}")
    private String aliasName;
    @Value("${batch-size}")
    private Integer batchSize;
    /**
     * 重建索引
     */
    @XxlJob("rebuildIndex")
    public void rebuildIndex(){
        // 索引不存在时创建索引
        if(!postIndexManager.indexExists(aliasName)){
            postIndexManager.createIndex(aliasName+ "_"+LocalDateTimeUtils.toEpochMillis(LocalDateTime.now()),0);
            addData();
            return;
        }
        // 索引存在时重建索引并切换别名
        GetAliasResponse aliasResponse = null;
        try {
            aliasResponse = esClient.indices().getAlias(r -> r.name(aliasName));
        } catch (IOException e) {
            throw new SearchServiceException(SearchServiceExpCode.GET_ALIAS_INDEX_ERROR);
        }
        String oldIndexName = aliasResponse.result().keySet().iterator().next();
        postIndexManager.switchAlias(oldIndexName, aliasName+ "_"+LocalDateTimeUtils.toEpochMillis(LocalDateTime.now()));
        addData();
    }
    private void addData(){
        List<Long> postMetaIds = tPostMetaService.findAll();
        if(ObjectUtils.isEmpty(postMetaIds)){
            return;
        }
        List<SearchServiceException> exceptions = new ArrayList<>();
        // 批量插入数据
        for (int i = 0; i < postMetaIds.size(); i += batchSize){
            List<Long> batchIds = postMetaIds.subList(i, Math.min(i + batchSize, postMetaIds.size()));
            LambdaQueryWrapper<TPostMeta> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(TPostMeta::getId, batchIds);
            List<PostInsertDto> insertDtos = tPostMetaService.list(queryWrapper).stream().map(this::convert).toList();
            for (PostInsertDto insertDto : insertDtos){
                try {
                    elasticInsertUtils.insertPost(insertDto);
                }catch (SearchServiceException e){
                    exceptions.add(e);
                }
            }
        }
        // 打印所有插入错误的异常
        if(!ObjectUtils.isEmpty(exceptions)){
            exceptions.forEach(XxlJobHelper::log);
        }
    }
    private PostInsertDto convert(TPostMeta postMeta){
        PostInsertDto postInsertDto = new PostInsertDto();
        BeanUtils.copyProperties(postMeta, postInsertDto);
        postInsertDto.setMetaId(postMeta.getId());
        return postInsertDto;
    }
}
